﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using PTCapture.Support;
using PTCapture.Support.Angles;
using PTCapture.PatientInfo;
using System.Drawing.Imaging;

namespace PTCapture.UserControls
{
    public partial class SnapshotDrawer : UserControl
    {
        #region Fields

        /// <summary>
        /// Size of elipse bounding angle
        /// </summary>
        const int recSize = 10;

        /// <summary>
        /// Color user has picked
        /// </summary>
        Color pickedColor;

        /// <summary>
        /// Current moise point
        /// </summary>
        Point currentMouse;

        /// <summary>
        /// Drawer for user angles
        /// </summary>
        UserAngleManager angleDrawer;

        /// <summary>
        /// Image we are drawing on.
        /// </summary>
        string imageSource;

        #endregion

        #region Delegates

        /// <summary>
        /// Tie to parent form to assign paths on selection
        /// </summary>
        /// <param name="videoPath"></param>
        /// <param name="imagePath"></param>
        /// <returns></returns>
        public delegate bool customHandler();
        public event customHandler MadeExercise;

        #endregion

        #region Initialization

        /// <summary>
        /// Constructor
        /// </summary>
        public SnapshotDrawer()
        {
            InitializeComponent();

            pictureBox1.MouseClick += new MouseEventHandler(pictureBox1_MouseClick);
            pictureBox1.MouseLeave += new EventHandler(pictureBox1_MouseLeave);
            pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);
            pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
            cblAngles.ItemCheck += new ItemCheckEventHandler(cblAngles_ItemCheck);

            // Drag drop
            
            this.AllowDrop = true;
            this.DragEnter += new DragEventHandler(SnapshotDrawer_DragEnter);
            this.DragDrop += new DragEventHandler(SnapshotDrawer_DragDrop);

            angleDrawer = new UserAngleManager();

            colorDialog1.AllowFullOpen = false;
            pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;

            colorDialog1.Color = Color.Red;
            pickedColor = colorDialog1.Color;
            pnlColor.BackColor = pickedColor;
        }

        #endregion

        #region Controls

        /// <summary>
        /// DragnDrop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SnapshotDrawer_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        /// <summary>
        /// DragnDrop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SnapshotDrawer_DragDrop(object sender, DragEventArgs e)
        {
            int x = this.PointToClient(new Point(e.X, e.Y)).X;
            int y = this.PointToClient(new Point(e.X, e.Y)).Y;

            if (x >= pictureBox1.Location.X &&
                x <= pictureBox1.Location.X + pictureBox1.Width &&
                y >= pictureBox1.Location.Y &&
                y <= pictureBox1.Location.Y + pictureBox1.Height)
            {
                ListItem files = (ListItem)e.Data.GetData(typeof(ListItem));
                pictureBox1.Load(files.Value);

                imageSource = files.Value;
            }
        }

        /// <summary>
        /// Change visibility
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cblAngles_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (e.NewValue == CheckState.Checked)
            {
                angleDrawer.angles[e.Index].Visible = true;
            }
            else
            {
                angleDrawer.angles[e.Index].Visible = false;
            }

            pictureBox1.Refresh();
        }

        /// <summary>
        /// Change mouse for in progress drawing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (angleDrawer.inProgressAngle != null)
            {
                currentMouse = e.Location;
                pictureBox1.Refresh();
            }
        }

        /// <summary>
        /// Draw picture box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            // Draw completed angles
            for (int i = 0; i < angleDrawer.angles.Count; i++)
            {
                if (angleDrawer.angles[i].Visible)
                {
                    using (Pen pen = new Pen(angleDrawer.angles[i].DrawColor, 2.0f))
                    {
                        e.Graphics.DrawLine(pen, angleDrawer.angles[i].A.Value, angleDrawer.angles[i].B.Value);
                        e.Graphics.DrawLine(pen, angleDrawer.angles[i].B.Value, angleDrawer.angles[i].C.Value);

                        PaintArcs(e.Graphics, pen, angleDrawer.angles[i].A.Value, angleDrawer.angles[i].B.Value, angleDrawer.angles[i].C.Value, angleDrawer.angles[i].Acute);
                    }
                }
            }

            // Draw in progress angle
            if (angleDrawer.inProgressAngle != null)
            {
                using (Pen pen = new Pen(pickedColor, 2.0f))
                {
                    if (angleDrawer.inProgressAngle.A.HasValue)
                    {
                        if (angleDrawer.inProgressAngle.B.HasValue)
                        {
                            e.Graphics.DrawLine(pen, angleDrawer.inProgressAngle.A.Value, angleDrawer.inProgressAngle.B.Value);
                            e.Graphics.DrawLine(pen, angleDrawer.inProgressAngle.B.Value, currentMouse);

                            PaintArcs(e.Graphics, pen, angleDrawer.inProgressAngle.A.Value, angleDrawer.inProgressAngle.B.Value, currentMouse, chkAcuteAngles.Checked);
                        }
                        else
                        {
                            e.Graphics.DrawLine(pen, angleDrawer.inProgressAngle.A.Value, currentMouse);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Reset in progress angle
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_MouseLeave(object sender, EventArgs e)
        {
            angleDrawer.inProgressAngle = null;

            pictureBox1.Refresh();
        }

        /// <summary>
        /// Add a point to an angle
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_MouseClick(object sender, MouseEventArgs e)
        {
            UserAngle a = angleDrawer.Click(e.Location, pickedColor, chkAcuteAngles.Checked);

            // Not null when created
            if (a != null)
            {
                cblAngles.Items.Add(string.Format("Angle {0}*, {1}, {2}", Math.Round(a.Angle), (a.Acute ? "Acute" : "Obtuse"), a.DrawColor), true);
            }

            pictureBox1.Refresh();
        }

        /// <summary>
        /// Change color
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnColorPicker_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                pickedColor = colorDialog1.Color;
                pnlColor.BackColor = pickedColor;
            }
        }

        /// <summary>
        /// Delete checked angles
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDelete_Click(object sender, EventArgs e)
        {
            for (int i = cblAngles.CheckedIndices.Count - 1; i >= 0; i--)
            {
                angleDrawer.angles.RemoveAt(cblAngles.CheckedIndices[i]);
                cblAngles.Items.RemoveAt(cblAngles.CheckedIndices[i]);
            }
        }

        /// <summary>
        /// Convert image to an exercise for a patient
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMakeExercise_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.DrawImage(pictureBox1.Image, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));

                // Redraw completed angles since it isn't part of the picture boxes image
                for (int i = 0; i < angleDrawer.angles.Count; i++)
                {
                    if (angleDrawer.angles[i].Visible)
                    {
                        using (Pen pen = new Pen(angleDrawer.angles[i].DrawColor, 2.0f))
                        {
                            g.DrawLine(pen, angleDrawer.angles[i].A.Value, angleDrawer.angles[i].B.Value);
                            g.DrawLine(pen, angleDrawer.angles[i].B.Value, angleDrawer.angles[i].C.Value);

                            PaintArcs(g, pen, angleDrawer.angles[i].A.Value, angleDrawer.angles[i].B.Value, angleDrawer.angles[i].C.Value, angleDrawer.angles[i].Acute);
                        }
                    }
                }
            }

            string[] splitFileName = imageSource.Split('\\');
            string newFileName = string.Format("{0}\\{1}_MadeExercise_{2}.png", GlobalVariables.DrawingPath, splitFileName[splitFileName.Length - 1].Replace(".png", ""), DateTime.Now.ToString("yyyyMMdd_hhmmss"));
            bmp.Save(newFileName, ImageFormat.Png);

            GlobalVariables.SelectedPatient.AssignedExercises.Add(new AssignedExercise(newFileName, DateTime.Now, DateTime.Now.AddDays(14), ""));
            MadeExercise();
        }

        #endregion

        #region Support

        /// <summary>
        /// Paint lines and arcs with designated values.
        /// </summary>
        /// <param name="g"></param>
        /// <param name="pen"></param>
        /// <param name="A"></param>
        /// <param name="B"></param>
        /// <param name="C"></param>
        /// <param name="acute"></param>
        private void PaintArcs(Graphics g, Pen pen, Point A, Point B, Point C, bool acute)
        {
            Font f = new System.Drawing.Font(FontFamily.GenericMonospace, 12.0f, FontStyle.Bold);
            SolidBrush b = new SolidBrush(pickedColor);
            PointF p = new PointF(B.X + (recSize * 1), B.Y + (recSize * 1));

            // Angle between the two user arms
            double sweepAngle = MathFunctions.GetAngle(A, B, C);

            // With small sweep angles and angleFromXAxis != 0, we get errors. Just bail out.
            if (sweepAngle < 0.5f)
            {
                return;
            }

            // Angle between the first arm and the positive x axis for offsetting where we start the sweep
            Point newPoint = new Point(B.X + 10, B.Y);
            double angleFromXAxis = MathFunctions.GetAngle(A, B, newPoint);

            // Check area
            double area = MathFunctions.GetArea(A.X, A.Y, B.X, B.Y, C.X, C.Y);
            if (acute)
            {
                // Straight line
                if (area == 0)
                {
                }
                //Counter-clockwise
                else if (area < 0)
                {
                    // Line slants down
                    if (A.Y <= B.Y)
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)-angleFromXAxis, (float)sweepAngle);
                    }
                    // Line slants up
                    else
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)angleFromXAxis, (float)sweepAngle);
                    }
                }
                // Clockwise
                else
                {
                    // Line slants down
                    if (A.Y <= B.Y)
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)-angleFromXAxis, (float)-sweepAngle);
                    }
                    // Line slants up
                    else
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)angleFromXAxis, (float)-sweepAngle);
                    }
                }

                g.DrawString(string.Format("{0}", Math.Round(sweepAngle)), f, b, p);
            }
            else
            {
                // Straight line
                if (area == 0)
                {
                }
                //Counter-clockwise
                else if (area < 0)
                {
                    // Line slants down
                    if (A.Y <= B.Y)
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)-angleFromXAxis, (float)-(360 - sweepAngle));
                    }
                    // Line slants up
                    else
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)angleFromXAxis, (float)-(360 - sweepAngle));
                    }
                }
                // Clockwise
                else
                {
                    // Line slants down
                    if (A.Y <= B.Y)
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)-angleFromXAxis, (float)(360 - sweepAngle));
                    }
                    // Line slants up
                    else
                    {
                        g.DrawArc(pen, (int)B.X - recSize, (int)B.Y - recSize, recSize * 2, recSize * 2,
                            (float)angleFromXAxis, (float)(360 - sweepAngle));
                    }
                }

                g.DrawString(string.Format("{0}", Math.Round(360 - sweepAngle)), f, b, p);
            }
        }

        #endregion
    }
}
